using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using AgilePlannerDT.Display;
using AgilePlannerDT.Utils;
using AgilePlannerDT.Data;
using System.Windows.Media.Animation;
using System.Text.RegularExpressions;
using AgilePlannerDT.Display.CustomWidgets;
using System.Windows.Ink;
using System.IO;
using AgilePlannerDT.Application;
using AgilePlannerDT.Display.Events;
using AgilePlannerDT.Data.Impl;
using AgilePlannerDT.Display.ValidationRules;
using System.Windows.Media.Effects; 

namespace AgilePlannerDT.Display.Impl
{
    /// <summary>
    /// Interaction logic for StoryCard.xaml
    /// </summary>

    public partial class StoryCardDisplayObjectImpl : DisplayObjectImpl, StoryCardDisplayObject
    {
        #region Constants

        protected static readonly double DEFAULT_ASPECT_RATIO = 3 / 2;
        protected static readonly double DEFAULT_SEPARATOR_SPACING = 25;

        #endregion

        #region Attributes

        #region Visual Children

        protected List<Line> separators = new List<Line>();
        protected List<TextBox> textboxes = new List<TextBox>();
        protected DeleteIcon deleteIcon;
        protected EditIcon editIcon;
        protected EditingModeIcon editingModeIcon;
        protected HandwritingModeIcon handwritingModeIcon;
        protected DropShadowEffect highlightShadowEffect; 

        #endregion

        protected StoryCard storyCard;
        bool isMinimized = false;
        bool isHandwritingEnabled = false;
        Boolean isTextArea = false;
        bool disabled = false;  //used to keep cards from switching state within a StateArea

        //calculate the delte X and delta Y while resizing story cards
   //     double resizeX = 0;
   //     double resizeY = 0;
        bool isInitalizeCardOwnerRunning = false;
        bool  isLocalCall=true;

        double orignialLeft, originalTop;

        //   bool nameTextBoxKeyDown = false;
        //     bool descriptionTextBoxKeyDown = false;

        bool TriggerDropEventAfterAnimation = true;
        protected AgilePlannerApplication parentWindow;

        private StoryCardDisplayObjectImplAutomationPeer peer;

        public delegate Point GetPosition(Point p, UIElement element);

        #endregion

        #region Constructors

        public StoryCardDisplayObjectImpl(StoryCard sc, AgilePlannerApplication mainWindow, Color color)
            : base(mainWindow)
        {
            //standard init
            InitializeComponent();
            this.descriptionInkCanvas.DataContext = this;
            this.parentWindow = mainWindow;
           
            this.storyCard = sc;
            //set the context for the data bindings
            DataContext = this;
       //     this.descriptionInkCanvas.DataContext = this;
            

            center = new Point(CardConstants.STORYCARD_DEFAULT_WIDTH / 2, CardConstants.STORYCARD_DEFAULT_HEIGHT / 2 );
            isTossingEnabled = true;
            isRNTEnabled = true;



            //storycard specific init
            InitializeTransformations();
            InitializeAnimations();

            //create rotation around the center of the card
            rotate.CenterX = CardConstants.STORYCARD_DEFAULT_WIDTH / 2;
            rotate.CenterY = CardConstants.STORYCARD_DEFAULT_HEIGHT / 2;

            //scaling
            //         scale.CenterX = CardConstants.STORYCARD_DEFAULT_WIDTH / 2;
            //         scale.CenterY = CardConstants.STORYCARD_DEFAULT_HEIGHT / 2;

            //move the card to the stored position
            trans.X = StoryCardData.LocationX * Properties.Settings.Default.Scale;
            trans.Y = StoryCardData.LocationY * Properties.Settings.Default.Scale;
            rotate.Angle = StoryCardData.RotationAngle;

            MinHeight = CardConstants.STORYCARD_DEFAULT_HEIGHT;
            MinWidth = CardConstants.STORYCARD_DEFAULT_WIDTH;
            Background = new SolidColorBrush(color);

            //initialize highlight shadow effect
            highlightShadowEffect = new System.Windows.Media.Effects.DropShadowEffect();
            highlightShadowEffect.Color = Colors.Red;
            highlightShadowEffect.ShadowDepth = 15;



            //bind 
            InitializeDataBinding();
            InitializeTextBoxes();
            InitializeComboBoxes();
            InitializeButtons();
            InitializeSeparators();

            translateOnlyArea.Opacity = 0;
           

            pin.Opacity = 0;
            pin.Click += new RoutedEventHandler(pin_Click);

            highlightTextBlock.Text = ID.ToString();
            highlightTextBlock.Opacity = 0;

            //restore the handwriting
            if (storyCard.HandwritingImage != null)
            {
                if (storyCard.HandwritingImage.Length > 0)
                {
                    //create a new stream with the values of the previously saved
                    //byte array
                    MemoryStream bis = new MemoryStream(storyCard.HandwritingImage);

                    //recreate the strokes from the stream
                    StrokeCollection strokes = new StrokeCollection(bis);

                    descriptionInkCanvas.Strokes = strokes;
                }
            }

            animationStoryBoard.Completed += new EventHandler(animationStoryBoard_Completed);


            if (this.storyCard.Height == CardConstants.DEFAULT_MINIMIZED_CARD_HEIGHT)
            {
                isLocalCall = true;
                CardMinimized(false);
                isLocalCall = false;
            }
            else
            {
                double dx = storyCard.Width - CardConstants.STORYCARD_DEFAULT_WIDTH;
                double dy = storyCard.Height - CardConstants.STORYCARD_DEFAULT_HEIGHT;
                this.Resize(ref dx, ref dy);
                
                //change the center of rotationTransformation
                this.rotate.CenterX = Width / 2;
                this.rotate.CenterY = this.Height / 2;

                //      this.rotate.CenterX = this.Width / 2;
          //      this.rotate.CenterY = this.Height / 2;
            //    this.UpdateLayout();
            }
            peer = new StoryCardDisplayObjectImplAutomationPeer(this);
        }

        private void InitializeDataBinding()
        {
            Binding nameTextBinding = new Binding("Name") { Source = this.storyCard };
            nameTextBox.SetBinding(TextBox.TextProperty, nameTextBinding);
           
            Binding mostLikelyTextBinding = new Binding("MostlikelyEstimate") { Source = this.storyCard};
            mostLikelyTextBinding.NotifyOnValidationError = true;
            mostLikelyTextBinding.ValidationRules.Add(new NumericValuesOnlyRule());
            this.mostlikelyTextBox.SetBinding(TextBox.TextProperty, mostLikelyTextBinding);

            Binding actualTextBinding = new Binding("ActualEffort") { Source = this.storyCard};
            actualTextBinding.NotifyOnValidationError = true;
            actualTextBinding.ValidationRules.Add(new NumericValuesOnlyRule());
            this.actualTextBox.SetBinding(TextBox.TextProperty, actualTextBinding);

            Binding descriptionTextBinding = new Binding("Description") { Source = this.storyCard };
            this.descriptionTextBox.SetBinding(TextBox.TextProperty, descriptionTextBinding);
          
            //Binding mostLikelyLabelBinding = new Binding("Background") {Source = this.storyCard };
            //this.mostlikelyLabel.SetBinding(TextBox.BackgroundProperty, mostLikelyLabelBinding);

            //Binding actualLabelBinding = new Binding("Background") { Source = this.storyCard};
            //this.actualLabel.SetBinding(TextBox.BackgroundProperty, actualLabelBinding);
        }
        //<TextBox.Text>
        //            <Binding Path="ActualEffort" NotifyOnValidationError="True">
        //                <Binding.ValidationRules>
        //                    <vr:NumericValuesOnlyRule />
        //                </Binding.ValidationRules>
        //            </Binding>
        //        </TextBox.Text>
        //<TextBox.Text> 
        //            <Binding Path="MostlikelyEstimate" NotifyOnValidationError="True" >
        //                <Binding.ValidationRules>
        //                    <vr:NumericValuesOnlyRule />
        //                </Binding.ValidationRules>
        //            </Binding>
        //        </TextBox.Text>

        #endregion

        #region Properties

        public Color CardColor
        {
            get
            {
                BrushConverter bc = new BrushConverter();

                String clr = (String)bc.ConvertTo(Background, typeof(string));

                ColorConverter cc = new ColorConverter();

                return (Color)cc.ConvertFrom(clr);
            }

            set
            {
                SolidColorBrush scb = new SolidColorBrush(value);

                Background = scb;
                nameTextBox.Background = scb;
                mostlikelyTextBox.Background = scb;
                actualTextBox.Background = scb;
                ownerComboBox.Background = scb;
                ownerComboBox_1.Background = scb;
                descriptionTextBox.Background = scb;
                if (!value.Equals(CardConstants.TRANSPARENT))//for text area, private changing the backgound to transparent;
                    StoryCardData.Background = value;
            }
        }

        public override long ID
        {
            get { return storyCard.ID; }
            set { storyCard.ID = value; }
        }

        public StoryCard StoryCardData
        {
            get { return storyCard; }
            set { storyCard = value; }
        }

        public override long ParentID
        {
            get { return storyCard.Parent; }
            set { storyCard.Parent = value; }
        }

        #endregion

        #region Visual Children Eventhandler

        private void pin_Click(object sender, RoutedEventArgs e)
        {
            animationStoryBoard.Stop(this);
            PinStoryCard();
        }

        /**
         * This section of code cycles the card's status sequentially
         * from Defined -> ToDo -> InProgress -> Complete -> Accepted
         * and updates the button's color appropriately.  For colors
         * and possible states, see CardConstants under Data.
         */
        private void statusButton_Click(object sender, RoutedEventArgs e)
        {
            if (!disabled)
            {
                if (StoryCardData.Status.Equals(CardConstants.STATUS_ACCEPTED))
                {
                    UpdateStatusButton(CardConstants.STATUS_DEFINED, CardConstants.STATUS_DEFINED_COLOR);
                }
                else if (StoryCardData.Status.Equals(CardConstants.STATUS_IN_PROGRESS))
                {
                    UpdateStatusButton(CardConstants.STATUS_COMPLETED, CardConstants.STATUS_COMPLETED_COLOR);
                }
                else if (StoryCardData.Status.Equals(CardConstants.STATUS_COMPLETED))
                {
                    UpdateStatusButton(CardConstants.STATUS_ACCEPTED, CardConstants.STATUS_ACCEPTED_COLOR);
                }
                else if (StoryCardData.Status.Equals(CardConstants.STATUS_DEFINED))
                {
                    UpdateStatusButton(CardConstants.STATUS_IN_PROGRESS, CardConstants.STATUS_IN_PROGRESS_COLOR);
                }
            }

        }

        private void switchClearButton_Click(object sender, RoutedEventArgs e)
        {
            if (descriptionInkCanvas.EditingMode == InkCanvasEditingMode.Ink)
            {
                descriptionInkCanvas.EditingMode = InkCanvasEditingMode.EraseByStroke;
                switchClearButton.Content = deleteIcon;
            }
            else
            {
                descriptionInkCanvas.EditingMode = InkCanvasEditingMode.Ink;
                switchClearButton.Content = editIcon;
            }
        }

        private void animationStoryBoard_Completed(object sender, EventArgs e)
        {
            if (translateXAnimation.KeyFrames.Count > 0)
                trans.X = translateXAnimation.KeyFrames[translateXAnimation.KeyFrames.Count - 1].Value;

            if (translateYAnimation.KeyFrames.Count > 0)
                trans.Y = translateYAnimation.KeyFrames[translateYAnimation.KeyFrames.Count - 1].Value;

            //if the card was only translated you don't have to update the rotation angle!
            if (rotateAnimation.KeyFrames.Count > 0)
                rotate.Angle = rotateAnimation.KeyFrames[rotateAnimation.KeyFrames.Count - 1].Value;

            //clear the keyframes, they are no longer needed
            translateXAnimation.KeyFrames.Clear();
            translateYAnimation.KeyFrames.Clear();
            rotateAnimation.KeyFrames.Clear();

            object before = StoryCardData.Clone();

            StoryCard after = (StoryCard)StoryCardData.Clone();
            after.LocationX = trans.X / Properties.Settings.Default.Scale;
            after.LocationY = trans.Y / Properties.Settings.Default.Scale;
            after.RotationAngle = rotate.Angle;

            //fire event
            Console.WriteLine("this is " + this.ID + ", " + this.TriggerDropEventAfterAnimation);
            if (this.TriggerDropEventAfterAnimation)
                IndexCardDropped(this, new IndexCardDropEventArgs(ID, ParentID, CenterAbsolute, StoryCardData.RotationAngle, before, after));
            this.TriggerDropEventAfterAnimation = true;
            Console.WriteLine("this is " + this.ID + " set to true in Anmiation COmplete ");
        }

        private void VisualChildren_PreviewMouseMove(object sender, RoutedEventArgs e)
        {
            OnMouseMove((MouseEventArgs)e);
        }

        private void VisualChildren_PreviewMouseLeftButtonDown(object sender, RoutedEventArgs e)
        {
            OnMouseLeftButtonDown((MouseButtonEventArgs)e);
        }

        private void VisualChildren_PreviewMouseLeftButtonUp(object sender, RoutedEventArgs e)
        {
            OnMouseLeftButtonUp((MouseButtonEventArgs)e);

            //ownerTextBox will cause strang UI problem
            if (sender is TextBox)
                ((TextBox)sender).SelectAll();
        }

        private void textBox_GotFocus(object sender, RoutedEventArgs e)
        {
            //Highlight the textbox on focus

            ((TextBox)sender).BorderThickness = new Thickness(2, 2, 2, 2);
            if (this.isTextArea && sender.Equals(descriptionTextBox))
                ((TextBox)sender).Background = Brushes.Black;
            else
                ((TextBox)sender).Background = Brushes.White;
        }

        private void textBox_LostFocus(object sender, RoutedEventArgs e)
        {
            //hide the textbox
            ((TextBox)sender).BorderThickness = new Thickness(0, 0, 0, 0);
            ((TextBox)sender).Background = Background;
            if (this.isTextArea && ((TextBox)sender).Text.Equals(""))
                ((TextBox)sender).Text = "text area";
        }

        private void ownerComboBox_LostFocus(object sender, RoutedEventArgs e)
        {

     /*       string owner = ((ComboBox)sender).Text;
            if (!ownerComboBox.Items.Contains(owner))
            {
                int index = (Owner.add(owner)
                    ? ownerComboBox.Items.Add(owner)
                    : ownerComboBox.Items.IndexOf(owner));
                ownerComboBox.SelectedIndex = index;
            }*/
        }

        private void numericTextBox_ValidationError(object sender, ValidationErrorEventArgs e)
        {
            ((TextBox)sender).Undo();
        }


        #endregion

        #region Member functions

        public void HandwritingEnlarge()
        {
            Fading(1, CardConstants.STORYCARD_HANDWRITING_ENLARGE_SCALE * Properties.Settings.Default.Scale, true);
        }

        public void HandwritingShrink()
        {
            Fading(CardConstants.STORYCARD_HANDWRITING_ENLARGE_SCALE * Properties.Settings.Default.Scale, Properties.Settings.Default.Scale, true);
        }

        public override void Select()
        {

            if (IsSelected)
            {
                IsSelected = false;
            //    this.BorderThickness = new Thickness(0);
                this.Effect = null;
                ////see whether this card is a textarea. 
                //if (!isTextArea)
                //    this.BorderBrush = Brushes.Black;
                //else
                //    this.BorderBrush = Brushes.Transparent;
            }
            else
            {
                IsSelected = true;
             //   this.grid..
                this.Effect = highlightShadowEffect;
                //this.BorderBrush = new SolidColorBrush(CardConstants.CARD_SELECTED_BORDER);
                //this.BorderThickness = new Thickness(3);
            }
        }

        public override void Highlight()
        {
            if (isHighlighted)
            {
                highlightTextBlock.Opacity = 0;
                isHighlighted = false;
            }
            else
            {
                highlightTextBlock.Opacity = 1;
                isHighlighted = true;
            }
        }

        public void ScaleForHandwriting(bool enlarge)
        {
            scale.CenterX = center.X;
            scale.CenterY = center.Y;

            if (enlarge)
            {
                scale.ScaleX = 3;
                scale.ScaleY = 3;
            }
            else
            {
                scale.ScaleX = 1;
                scale.ScaleY = 1;
            }
        }

        public override void Resize(ref double dx, ref double dy)
        {
            //check if the resize would decrease the
            //size below minimum (as we force an aspect ratio its all or
            //nothing)
            //and don't check for ActualWidth and Height as they both
            //return 0 before the card is displayed for the first time and
            //that would interfere with the initial resize on load!
 
       //     dx = currentX * Math.Cos(Util.ToRadians(angle)) + currentY * Math.Sin(Util.ToRadians(angle));
        //    dy = -currentX * Math.Sin(Util.ToRadians(angle)) + currentY * Math.Cos(Util.ToRadians(angle));
            if (((Height + dy) >= MinHeight))
            {
                Height += dy;
                //   Width += dx;

                //     highlight.Width += dx;
                //       highlight.Height += dy;

                canvas.Height += dy;
                //       canvas.Width += dx;

                grid.Height += dy;


                //refit the center 
                center.Y += dy / 2;



            }
            else
            {
                dy = 0;
            }

            if (((Width + dx) >= MinWidth))
            {

                Width += dx;

                canvas.Width += dx;
                grid.Width += dx;

                //refit the center
                center.X += dx / 2;


            }
            else
            {
                dx = 0;
            }
            
            IsDragged = false;
        }



        #endregion

        #region Custom Event Handling

        protected override void OnMouseLeave(MouseEventArgs e)
        {
            base.OnMouseLeave(e);

            //assure that the TOA is really gone
            translateOnlyArea.Opacity = 0;
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);
            //Console.WriteLine("Timestamp: "+e.Timestamp);
           //Console.WriteLine(Environment.TickCount);
            //   e.Timestamp

       //     RefitCenter(this.Width, this.Height);
            //get the location of the MouseDown relative to the card's upper left corner
            Point actual = e.GetPosition(this);

            #region Dot Voting
            /* Draw dot, only if voting session is enabled */
            if (parentWindow.IsVotingEnabled)
            {
                //Ellipse dot = new Ellipse();
                //dot.Stroke = System.Windows.Media.Brushes.Gray;
                //dot.Fill = System.Windows.Media.Brushes.Gray;
                //dot.Width = 25;
                //dot.Height = 25;
                //Canvas.SetTop(dot, actual.Y - 10);
                //Canvas.SetLeft(dot, actual.X - 10);
                //canvas.Children.Add(dot);
                drawVoteDot((int)actual.X, (int)actual.Y);
                this.app.Persister.VoteCard(new VoteDotObject(this.ID, (int) actual.X, (int) actual.Y));
                //can only vote once
                //don't do anything else during a voting session...
                return;
            }
            #endregion

            //bring it to front
            app.BringToFront(this);
            //Console.WriteLine(actual.X.ToString());               //this test was left uncommented!
            //if you move this card on top of other cards only
            //this one will react, otherwise you drag the rest with
            //you like a fish-net
            IsActive = true;

            if (!IsPinned)
            {
                //don't show the translate only area if the card
                //is pinned or it'll confuse the user during handwriting
                translateOnlyArea.Opacity = 1;
            }
            else
            {
                //if the card is pinned just quit the function
                return;
            }

            //if the card is currently in an animated movement this saves
            //the current position of the card and fires the DropEvent to notify
            //the application of the position update
            if (animationStoryBoard.GetCurrentState(this) == ClockState.Active)
            {
                //Yippie-Ki-Yay ... stops the card from jumping if
                //you click on label or resizerhandle
                rotate.Angle = (double)rotate.GetValue(RotateTransform.AngleProperty);
                trans.X = (double)trans.GetValue(TranslateTransform.XProperty);
                trans.Y = (double)trans.GetValue(TranslateTransform.YProperty);

                animationStoryBoard.Stop(this);

                //TODO change copies only!
                object before = StoryCardData.Clone();
                //StoryCardData.LocationX = trans.X;
                //StoryCardData.LocationY = trans.Y;
                //StoryCardData.RotationAngle = rotate.Angle;
                StoryCard after = (StoryCard)StoryCardData.Clone();

                after.LocationX = trans.X / Properties.Settings.Default.Scale;
                after.LocationY = trans.Y / Properties.Settings.Default.Scale;
                after.RotationAngle = rotate.Angle;

                IndexCardDropped(this, new IndexCardDropEventArgs(ID, ParentID, RelativeToAbsoluteCoordinates(actual), StoryCardData.RotationAngle, before, after));
            }

            //clear the list of keyframes or you'll get unexpected
            //results
            translateXAnimation.KeyFrames.Clear();
            translateYAnimation.KeyFrames.Clear();
            rotateAnimation.KeyFrames.Clear();

            IsTossed = false;
            //resize
            if (resizerHandle.IsInsideResizerHandleArea(e.GetPosition(resizerHandle)) && !isMinimized)
            {
                IsResized = true;
                IsTranslated = false;
                isDragged = false;      //some very strange behavior occurs without this
         //       this.originalTop = ((Canvas)(((AgilePlannerMainWindow)this.parentWindow).getCanvas())).GetTop(this);
                this.originalTop = this.trans.Y;
                this.orignialLeft = this.trans.X;
               
            }
            //translate only
            else if (translateOnlyArea.IsInsideTranslateOnlyArea(e.GetPosition(translateOnlyArea)))
            {
                IsTranslated = true;
                IsResized = false;
            }

            //RNT
            else
            {
                IsTranslated = false;
                IsResized = false;
            }

            previous = RelativeToAbsoluteCoordinates(actual);
            previousRelative = actual;

            startTime = DateTime.Now;  //for tossing

            //for tossing we watch the last few mouse coordinates
            recentPoints.Clear();
            recentTime.Clear();
            AddMousePoint(RelativeToAbsoluteCoordinates(actual));
            AddTimePoint(DateTime.Now);
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);

/*
            this.rotate.CenterX = this.Width / 2;
            this.rotate.CenterY = this.Height / 2;

            this.trans.X += Properties.Settings.Default.Scale*0.5*(resizeX*Math.Cos(Util.ToRadians(this.RotationAngle))-resizeY*Math.Sin(Util.ToRadians(this.RotationAngle))-resizeX);
            this.trans.Y += Properties.Settings.Default.Scale*0.5*(resizeX*Math.Sin(Util.ToRadians(this.RotationAngle))+resizeY*Math.Cos(Util.ToRadians(this.RotationAngle))-resizeY);
        //    this.UpdateLayout();
            
            this.resizeX = 0;
            this.resizeY = 0;*/
         //   this.refitCardCenterAndAbsolutePosition();
            object before = null;
            object after = null;

            translateOnlyArea.Opacity = 0;

            IsActive = false;

            if (IsPinned)
                return;

            Point actual = e.GetPosition(this);

            if (IsResized)
            {
                before = StoryCardData.Clone();
                after = StoryCardData.Clone();

                ((StoryCard)after).Width = Width;
                ((StoryCard)after).Height = Height;
                if ((int)(((StoryCard)before).Width) != (int)Width || (int)(((StoryCard)before).Height) != (int)Height)
                {//change the data object
                    this.StoryCardData.Width = Width ;
                    this.StoryCardData.Height = Height ;

                    if ((int)(((StoryCard)before).LocationX) != (int)(LocationX / Properties.Settings.Default.Scale) || (int)(((StoryCard)before).LocationY) != (int)(LocationY / Properties.Settings.Default.Scale))
                    {
                        this.StoryCardData.LocationX = LocationX / Properties.Settings.Default.Scale;
                        this.StoryCardData.LocationY = LocationY / Properties.Settings.Default.Scale;
                        after = StoryCardData.Clone();
                    }
                    StoryCardData.Notify(IndexCardDataObject.SIZE_PROPERTY, before, after);
                }
                IsResized = false;
                return;
            }

            if (IsDragged)
            {
                before = StoryCardData.Clone();
                after = StoryCardData.Clone();

                ((StoryCard)after).LocationX = trans.X / Properties.Settings.Default.Scale;
                ((StoryCard)after).LocationY = trans.Y / Properties.Settings.Default.Scale;
                ((StoryCard)after).RotationAngle = rotate.Angle;

                peer.OnTransform(before, after);

                IsDragged = false;
            }

            AddMousePoint(RelativeToAbsoluteCoordinates(actual));
            AddTimePoint(DateTime.Now);

            //check if the movement was fast enough to count as tossing
            double length = Util.GetDistance2D(recentPoints[0], recentPoints[recentPoints.Count - 1]);

            if (!IsResized && IsTossingEnabled && (length > CardConstants.STATIC_FRICTION_COEFFICIENT))
            {
                IsTossed = true;

                //vector along which to move the card
                tossingVector = new Point(recentPoints[recentPoints.Count - 1].X - recentPoints[0].X,
                    recentPoints[recentPoints.Count - 1].Y - recentPoints[0].Y);

                //setting up the vector for the initial moment of the tossing RNT
                initVector = new Point(recentPoints[recentPoints.Count - 1].X - CenterAbsolute.X,
                    recentPoints[recentPoints.Count - 1].Y - CenterAbsolute.Y);

                initAngle = RotationAngle;

        //        endTime = DateTime.Now;

                if (IsTranslated)
                {
                    ApplyTranslateOnlyTossing();
                }
                else
                {
                    ApplyRNTTossing();
                }
            }
            else
            {
                if (before != null && after != null)
                    //if the card is only moved and not tossed then fire the DropEvent
                    IndexCardDropped(this, new IndexCardDropEventArgs(ID, ParentID, RelativeToAbsoluteCoordinates(actual), StoryCardData.RotationAngle, before, after));
            }

            IsTranslated = false;

            //make sure that we don't have any old points in our watchlist
            recentPoints.Clear();
            recentTime.Clear();
        }

        protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
        {
   /*         //disable the double click function in the handwriting mode
            if (this.isHandwritingEnabled)
                return;

            base.OnMouseDoubleClick(e);
            this.minimizeCard();*/

        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
          //  e.Timestamp
            Point actual = RelativeToAbsoluteCoordinates(e.GetPosition(this));
            Point actualRelative = e.GetPosition(this);

            if (e.LeftButton.Equals(MouseButtonState.Pressed) && IsActive)
            {
                //don't do anything when the card is pinned but
                //update the last point
                if (IsPinned)
                {
                    previous = actual;
                    previousRelative = e.GetPosition(this);
                    AddMousePoint(actual);
                    AddTimePoint(DateTime.Now);
                    return;
                }

                //ignore very small movements (should help
                //compensate the imprecision of the DViTs)
                if (Util.GetDistance2D(previous, actual) < CardConstants.MIN_MOVEMENT_THRESHOLD)
                {
                    previous = actual;
                    previousRelative = e.GetPosition(this);
                    AddMousePoint(actual);
                    AddTimePoint(DateTime.Now);
                    return;
                }

                //TODO corrective movement
                if (IsResized)
                {
                    //determine the values for horizontal and vertical resize as
                    //the relative change between the previous mouse position and the actual
                    //on the card
                    double dx = actualRelative.X - previousRelative.X;
                    double dy = actualRelative.Y - previousRelative.Y;

                    //make sure to keep the 3/2 aspect ratio
                    /*                  if (dx / dy > DEFAULT_ASPECT_RATIO)
                                          dy = dx * 1 / DEFAULT_ASPECT_RATIO;
                                      else
                                          dx = dy * DEFAULT_ASPECT_RATIO;*/

            //       this.trans.X  += dx;
                 //  this.trans.Y -=dy;
                    Resize(ref dx, ref dy);
                    this.refitCardCenterAndAbsolutePosition(dx, dy);
                    (this.app).SynchronizeResizingCard(this, e.GetPosition((this.app).getCanvas()),0);
           
                }
                else
                {
                    IsDragged = true;
                    ApplyRNT(actual);
                    (this.app).SynchornizeMovingCard(this, e.GetPosition((this.app).getCanvas()),0);
           
                }

                //used for keeping track of the movement of the card
                AddMousePoint(actual);
                AddTimePoint(DateTime.Now);
                previous = actual;
                previousRelative = e.GetPosition(this);
            }
        }



        #endregion

        #region Helper functions

        private void PinStoryCard()
        {

            if (isPinned)
            {
                IsPinned = false;
                pin.Opacity = 0;
            }
            else
            {
                IsPinned = true;
                pin.Opacity = 1;
            }

        }

        private void HandwritingEnabled()
        {
            if (this.isHandwritingEnabled)
            {

                switchClearButton.IsHitTestVisible = false;
                switchClearButton.Opacity = 0;

                //Attention: use MemoryStream and ToArray otherwise
                //you will loose the data from the strokes (don't ask why
                //but Read only stores 0's in the array)

                if ((descriptionInkCanvas.Strokes != null) && (descriptionInkCanvas.Strokes.Count > 0))
                {
                    //create a new stream
                    MemoryStream bs = new MemoryStream();

                    //save the compressed strokes to the stream
                    descriptionInkCanvas.Strokes.Save(bs);

                    //copy the values from the stream to a
                    //byte array that will be asigned to the
                    //HandwritingImage
                    byte[] b = bs.ToArray();

                    if (b.Length != StoryCardData.HandwritingImage.Length)
                    {
                        StoryCardData.HandwritingImage = b;

                        InkAnalyzer inkAnalyzer = new InkAnalyzer();

                        inkAnalyzer.AddStrokes(descriptionInkCanvas.Strokes);
                        inkAnalyzer.SetStrokesType(descriptionInkCanvas.Strokes, StrokeType.Writing);

                        AnalysisStatus status = inkAnalyzer.Analyze();

                        if (status.Successful)
                        {
                            descriptionTextBox.Text = inkAnalyzer.GetRecognizedString();
                            StoryCardData.Description = descriptionTextBox.Text;
                        }
                    }
                }

                descriptionInkCanvas.IsHitTestVisible = false;
                HandwritingShrink();
                this.isHandwritingEnabled = false;

            }
            else
            {

                this.isHandwritingEnabled = true;
                switchClearButton.IsHitTestVisible = true;
                switchClearButton.Opacity = 1;

                descriptionInkCanvas.IsHitTestVisible = true;
                HandwritingEnlarge();
            }
        }


        private void UpdateStatusButton(string status, Color color)
        {
            //change the text and color for the status button
            TextBlock tb = new TextBlock();
            statusButton.Background = CreateHorizontalGradientBrush(color);
            tb.Text = status;
            tb.LayoutTransform = new RotateTransform(90, tb.ActualWidth / 2, tb.ActualHeight / 2);
            statusButton.Content = tb;
            StoryCardData.Status = status;
        }

        /// <summary>
        /// Used by StateArea to disable status bar firings.
        /// </summary>
        /// <param name="b">True = disable; False = enable</param>
        public void State_Override(bool b)
        {
            this.disabled = b;
        }

        private Brush CreateHorizontalGradientBrush(Color color)
        {
            LinearGradientBrush brush = new LinearGradientBrush();
            brush.StartPoint = new Point(0, 0.5);
            brush.EndPoint = new Point(1, 0.5);

            brush.GradientStops.Add(new GradientStop(color, 0));
            brush.GradientStops.Add(new GradientStop(Color.FromArgb(0, color.R, color.G, color.B), 1));

            return brush;
        }


        public void refreshCardTextBoxes()
        {
            this.actualTextBox.Text = this.StoryCardData.ActualEffort.ToString();
            this.mostlikelyTextBox.Text = this.StoryCardData.MostlikelyEstimate.ToString();
         //   this.ownerComboBox.Text = this.StoryCardData.CardOwner;
            this.InitializeCardOwner(this.StoryCardData.CardOwner);
            this.descriptionTextBox.Text = this.StoryCardData.Description;
            this.nameTextBox.Text = this.StoryCardData.Name;
            UpdateStatusButton(this.StoryCardData.Status, CardConstants.StatusButtonColor[this.StoryCardData.Status]);
        }

        #endregion

        public void setTriggerDropEventAfterAnimiationComplete(bool trigger)
        {
            this.TriggerDropEventAfterAnimation = trigger;
        }

        #region Initializations

        private void InitializeButtons()
        {

            //status button
            TextBlock tb = new TextBlock();
            tb.Text = StoryCardData.Status;
            tb.LayoutTransform = new RotateTransform(90, tb.ActualWidth / 2, tb.ActualHeight / 2);
            statusButton.Content = tb;

            if (StoryCardData.Status.Equals(CardConstants.STATUS_DEFINED))
                statusButton.Background = CreateHorizontalGradientBrush(CardConstants.STATUS_DEFINED_COLOR);
            else if (StoryCardData.Status.Equals(CardConstants.STATUS_IN_PROGRESS))
                statusButton.Background = CreateHorizontalGradientBrush(CardConstants.STATUS_IN_PROGRESS_COLOR);
            else if (StoryCardData.Status.Equals(CardConstants.STATUS_COMPLETED))
                statusButton.Background = CreateHorizontalGradientBrush(CardConstants.STATUS_COMPLETED_COLOR);
            else
                statusButton.Background = CreateHorizontalGradientBrush(CardConstants.STATUS_ACCEPTED_COLOR);

            statusButton.PreviewMouseMove += new MouseEventHandler(VisualChildren_PreviewMouseMove);
            statusButton.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonDown);
            statusButton.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonUp);
            statusButton.Click += new RoutedEventHandler(statusButton_Click);

            deleteCardButton.Click += new RoutedEventHandler(deleteCardButton_Click);

            //button to switch between erase and write mode of InkCanvas
            switchClearButton.Opacity = 0;
            switchClearButton.IsHitTestVisible = false;
            switchClearButton.Click += new RoutedEventHandler(switchClearButton_Click);

            double sizeX = switchClearButton.Width - switchClearButton.Padding.Left - switchClearButton.Padding.Right;
            double sizeY = switchClearButton.Height - switchClearButton.Padding.Top - switchClearButton.Padding.Bottom;

            deleteIcon = new DeleteIcon();
            deleteIcon.LayoutTransform = new ScaleTransform(sizeX / 800, sizeY / 600);
            editIcon = new EditIcon();
            editIcon.LayoutTransform = new ScaleTransform(sizeX / 800, sizeY / 600);

            switchClearButton.Content = editIcon;



            handwritingSwitchButton.Click += new RoutedEventHandler(handwritingSwitchButton_Click);
            editingModeIcon = new EditingModeIcon();
            editingModeIcon.LayoutTransform = new ScaleTransform(sizeX / 900, sizeY / 900);
            handwritingSwitchButton.Content = editingModeIcon;
            handwritingModeIcon = new HandwritingModeIcon();
            handwritingModeIcon.LayoutTransform = new ScaleTransform(sizeX / 900, sizeY / 900);

            //live update for TextBox input
            //        nameTextBox.TextChanged+=new TextChangedEventHandler(nameTextBox_TextChanged);
            descriptionTextBox.KeyUp += new KeyEventHandler(descriptionTextBox_KeyUp);
            nameTextBox.KeyUp += new KeyEventHandler(nameTextBox_KeyUp);

        }

        void descriptionTextBox_KeyUp(object sender, KeyEventArgs e)
        {
            this.app.Persister.LiveUpdate(new LiveUpdateDataObject(this.descriptionTextBox.Text, LiveUpdateDataObject.DESCRIPTION_TEXTBOX, this.ID));
        }

        void nameTextBox_KeyUp(object sender, KeyEventArgs e)
        {
            this.app.Persister.LiveUpdate(new LiveUpdateDataObject(this.nameTextBox.Text, LiveUpdateDataObject.NAME_TEXTBOX, this.ID));
        }

        void handwritingSwitchButton_Click(object sender, RoutedEventArgs e)
        {

            if (this.isHandwritingEnabled)
            {
                handwritingSwitchButton.Content = editingModeIcon;
            }
            else
            {
                handwritingSwitchButton.Content = handwritingModeIcon;
                this.isPinned = false;
            }
            PinStoryCard();
            HandwritingEnabled();
        }

        void deleteCardButton_Click(object sender, RoutedEventArgs e)
        {
            this.app.Delete(this);

            //    throw new NotImplementedException();
        }

        private void InitializeSeparators()
        {
            //only parts of a child that are inside
            //the grid are displayed so it doesn't matter how many seperators are
            //added
            Line separator;

            for (int i = 0; i < 30; i++)
            {
                separator = new Line();


                //first line is red
                if (i == 0)
                {

                    separator.X1 = -2500;
                    separator.X2 = CardConstants.STORYCARD_DEFAULT_WIDTH + 2500;
                    separator.Y1 = 35;
                    separator.Y2 = 35;
                    separator.Stroke = Brushes.Red;
                    separator.StrokeThickness = 2;
                }
                else
                {
                    separator.X1 = -2500;
                    separator.X2 = CardConstants.STORYCARD_DEFAULT_WIDTH + 2500;
                    separator.Y1 = 35 + i * DEFAULT_SEPARATOR_SPACING;
                    separator.Y2 = 35 + i * DEFAULT_SEPARATOR_SPACING;

                    separator.Stroke = Brushes.DarkGray;
                    separator.StrokeThickness = 1;
                }
                separators.Add(separator);

                overlay.Children.Add(separator);
            }
        }

        private void InitializeTextBoxes()
        {
            //Text="{Binding Path=storyCard.Name}"

            textboxes.Add(nameTextBox);
            textboxes.Add(descriptionTextBox);
            textboxes.Add(mostlikelyTextBox);
            textboxes.Add(actualTextBox);
        //    nameTextBox.da
            foreach (TextBox tb in textboxes)
                InitTextBox(tb);

            //check for valid input
            Validation.AddErrorHandler(this.mostlikelyTextBox, numericTextBox_ValidationError);
            Validation.AddErrorHandler(this.actualTextBox, numericTextBox_ValidationError);
        }

        private void InitTextBox(TextBox tb)
        {
            tb.GotFocus += new RoutedEventHandler(textBox_GotFocus);
            tb.LostFocus += new RoutedEventHandler(textBox_LostFocus);

            tb.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonDown);
            tb.PreviewMouseMove += new MouseEventHandler(VisualChildren_PreviewMouseMove);
            tb.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonUp);

            tb.BorderThickness = new Thickness(0);
            tb.Background = Background;

            tb.GotFocus += new RoutedEventHandler(tb_GotFocus);

            tb.LostFocus += new RoutedEventHandler(tb_LostFocus);

            tb.LostKeyboardFocus += new KeyboardFocusChangedEventHandler(tb_LostKeyboardFocus);

            tb.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(tb_GotKeyboardFocus);
        }

        void tb_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            //Console.WriteLine("got keyboard focus");
        }

        void tb_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            //Console.WriteLine("lost keyboard focus");
        }

        void tb_LostFocus(object sender, RoutedEventArgs e)
        {
            //Console.WriteLine("lost focus");
        }

        void tb_GotFocus(object sender, RoutedEventArgs e)
        {
            //Console.WriteLine("the text box got focus");
        }

        private void InitializeComboBoxes()
        {
      //      ownerComboBox.LostFocus += new RoutedEventHandler(ownerComboBox_LostFocus);
       //     ownerComboBox.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonDown);
     //       ownerComboBox.PreviewMouseMove += new MouseEventHandler(VisualChildren_PreviewMouseMove);
   //         ownerComboBox.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonUp);
            ownerComboBox.SelectionChanged += new SelectionChangedEventHandler(ownerComboBox_1_SelectionChanged);
           
            ownerComboBox.IsEditable = false;
            ownerComboBox_1.SelectionChanged += new SelectionChangedEventHandler(ownerComboBox_1_SelectionChanged);
         //   ownerComboBox.
    //        ownerComboBox_1.LostFocus += new RoutedEventHandler(ownerComboBox_LostFocus);
     //       ownerComboBox_1.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonDown);
     //       ownerComboBox_1.PreviewMouseMove += new MouseEventHandler(VisualChildren_PreviewMouseMove);
     //       ownerComboBox_1.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonUp);
            ownerComboBox_1.IsEditable = false;

            ownerComboBox_1.Items.Add("Unassigned");
            ownerComboBox.Items.Add("Unassigned");
            if (this.parentWindow.Project != null)
            {
                foreach (TeamMember o in this.parentWindow.Project.TeamMemberChildren)
                {
                    ownerComboBox_1.Items.Add((string) (o.Name));
                }
                foreach (TeamMember o in this.parentWindow.Project.TeamMemberChildren)
                {
                    ownerComboBox.Items.Add((string) (o.Name));
                }
            }
            ownerComboBox_1.BorderThickness = new Thickness(0);
            ownerComboBox_1.Background = Background;
            ownerComboBox.BorderThickness = new Thickness(0);
            ownerComboBox.Background = Background;

            InitializeCardOwner(this.StoryCardData.CardOwner);
        }

        void ownerComboBox_1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (isInitalizeCardOwnerRunning ||ownerComboBox_1.SelectedItem == null || ownerComboBox.SelectedItem == null)
                return;
            if(ownerComboBox_1.SelectedItem.Equals(ownerComboBox.SelectedItem)&&!ownerComboBox_1.SelectedItem.Equals("Unassigned"))
            {
               ((ComboBox)sender).SelectedItem="Unassigned";
               if (((ComboBox)sender).Name.Equals("ownerComboBox"))
                   StoryCardData.CardOwner = this.ownerComboBox_1.SelectedItem.ToString();
               else
                   StoryCardData.CardOwner = this.ownerComboBox.SelectedItem.ToString();
            }
            else if (ownerComboBox_1.SelectedItem.Equals("Unassigned")&&ownerComboBox.SelectedItem.Equals("Unassigned"))
                 StoryCardData.CardOwner = this.ownerComboBox.SelectedItem.ToString();
            else if (!ownerComboBox_1.SelectedItem.Equals("Unassigned") && ownerComboBox.SelectedItem.Equals("Unassigned"))
                StoryCardData.CardOwner = this.ownerComboBox_1.SelectedItem.ToString() ;
            else if (ownerComboBox_1.SelectedItem.Equals("Unassigned") && !ownerComboBox.SelectedItem.Equals("Unassigned"))
                StoryCardData.CardOwner = this.ownerComboBox.SelectedItem.ToString();
            else
              StoryCardData.CardOwner = this.ownerComboBox_1.SelectedItem.ToString() + " & " + this.ownerComboBox.SelectedItem.ToString();
         
        }
            

  
        

        public void switchStoryCardToTextArea()
        {
            //change the size of the components
            //      this.Height = 200;

            this.isTextArea = true;
            this.BorderThickness = new Thickness(0);
            this.MinHeight = 100;
            double dx = 0;
            double dy = this.MinHeight - this.Height;
            this.Resize(ref dx ,ref dy);
            this.refitCardCenterAndAbsolutePosition(dx, dy);
            this.CardColor = CardConstants.TRANSPARENT;
            this.canvas.Opacity = 1;
            //     this.canvas.IsEnabled = false;
            this.nameTextBox.Opacity = 0;
            this.deleteCardButton.Opacity = 0;
            this.handwritingSwitchButton.Opacity = 0;
            this.actualLabel.Opacity = 0;
            this.mostlikelyLabel.Opacity = 0;
        //    this.ownerLabel.Opacity = 0;
            this.statusButton.Opacity = 0;
            this.actualTextBox.Opacity = 0;
            this.mostlikelyTextBox.Opacity = 0;
            this.ownerComboBox.Opacity = 0;
            this.ownerComboBox_1.Opacity = 0;
            this.overlay.Opacity = 0;
            //   this.name
            this.nameTextBox.IsEnabled = false;
            this.mostlikelyTextBox.IsEnabled = false;
            this.actualTextBox.IsEnabled = false;
            this.ownerComboBox.IsEnabled = false;
            this.ownerComboBox_1.IsEditable = false;
            this.pin.IsEnabled = false;
            this.deleteCardButton.IsEnabled = false;
            this.handwritingSwitchButton.IsEnabled = false;
            this.translateOnlyArea.Opacity = 1;
            statusButton.IsEnabled = false;
            this.descriptionTextBox.Opacity = 1;
            this.descriptionTextBox.Foreground = Brushes.White;
            Grid.SetColumn(this.descriptionTextBox, 0);
            Grid.SetColumnSpan(this.descriptionTextBox, 6);
            Grid.SetRowSpan(this.descriptionTextBox, 3);
            Grid.SetRow(this.descriptionTextBox, 0);
            this.descriptionTextBox.FontSize = 38;
            this.translateOnlyArea.VerticalAlignment = VerticalAlignment.Top;


        }

        #endregion

        private void storycard_Loaded(object sender, RoutedEventArgs e)
        {

        }

        internal void UpdateTextBox(string text, int field)
        {
            if (field == LiveUpdateDataObject.DESCRIPTION_TEXTBOX)
                this.descriptionTextBox.Text = text;
            else if (field == LiveUpdateDataObject.NAME_TEXTBOX)
                this.nameTextBox.Text = text;
        }

        internal void InitializeCardOwner(string cardOwner)
        {
            isInitalizeCardOwnerRunning = true;
            Regex r = new Regex(" & ");
            string[] results = r.Split(cardOwner);
            if (results.Length == 1)
            {
                ownerComboBox_1.SelectedItem = "Unassigned";
                ownerComboBox.SelectedItem = "Unassigned";
                ownerComboBox_1.SelectedItem = results[0];

                isInitalizeCardOwnerRunning = false;
            }

            else
            {
                ownerComboBox_1.SelectedItem = results[0];
                ownerComboBox.SelectedItem = results[1];

                isInitalizeCardOwnerRunning = false;
            }
        }

        #region Automation

        /// <summary>
        /// Provides an implementation of this control as per the WPF structure.
        /// </summary>
        /// <returns>Returns a new AutomationPeer for this type.</returns>
        protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
        {
            return peer;
            //return new StoryCardDisplayObjectImplAutomationPeer(this);
        }

        public class StoryCardDisplayObjectImplAutomationPeer : DisplayObjectImplAutomationPeer
        {
            StoryCardDisplayObjectImpl host;

            /// <summary>
            /// Inits a new instance from the base class.
            /// </summary>
            /// <param name="control">The calling control.</param>
            public StoryCardDisplayObjectImplAutomationPeer(StoryCardDisplayObjectImpl control)
                : base(control)
            {
                host = control;
            }

            public void OnTransform(object before, object after)
            {
                //if(ListenerExists)
                    //this.RaiseAutomationEvent(System.Windows.Automation.Peers.AutomationEvents.PropertyChanged);
                /*System.Windows.Rect bef = new System.Windows.Rect(
                    ((StoryCardDataObject) before).LocationX,
                    ((StoryCardDataObject) before).LocationY,
                    ((StoryCardDataObject) before).Width,
                    ((StoryCardDataObject) before).Height);
                System.Windows.Rect aft = new System.Windows.Rect(
                    ((StoryCardDataObject) after).LocationX,
                    ((StoryCardDataObject) after).LocationY,
                    ((StoryCardDataObject) after).Width,
                    ((StoryCardDataObject) after).Height);*/

                this.RaisePropertyChangedEvent(System.Windows.Automation.AutomationElement.BoundingRectangleProperty, null, null);//bef, aft);
            }

            /// <summary>
            /// This is the name of the UIElement associated with the AutomationPeer.
            /// </summary>
            /// <returns>The name of this control type.</returns>
            protected override string GetClassNameCore()
            {
                return "StoryCardDisplayObjectImpl";
            }

            /// <summary>
            /// Sets the AutomationID
            /// </summary>
            /// <returns>The name of this display object.</returns>
            protected override string GetAutomationIdCore()
            {
                return "StoryCard:" + host.ID;
            }

            /// <summary>
            /// Storycards cannot be resized if they are pinned or minimized.
            /// </summary>
            public override bool CanResize
            {
                get
                {
                    return (!host.isPinned && !host.isMinimized);
                }
            }

            /// <summary>
            /// Moves the storycard and triggers a dropped card event if successful.
            /// </summary>
            /// <param name="x">X-movement amount.</param>
            /// <param name="y">Y-movement amount.</param>
            public override void Move(double x, double y)
            {
                object before = host.StoryCardData.Clone();

                base.Move(x, y);

                object after = host.StoryCardData.Clone();

                ((StoryCard)after).LocationX = host.trans.X / Properties.Settings.Default.Scale;
                ((StoryCard)after).LocationY = host.trans.Y / Properties.Settings.Default.Scale;

                if (before !=  after)
                    host.IndexCardDropped(host, new IndexCardDropEventArgs(host.ID, host.ParentID, 
                        host.CenterAbsolute, host.StoryCardData.RotationAngle, before, after));
            }

            /// <summary>
            /// Rotates the storycard the specified number of degrees and propagates the change.
            /// </summary>
            /// <param name="degrees">The number of degrees by which to rotate the card.</param>
            public override void Rotate(double degrees)
            {
                object before = host.StoryCardData.Clone();

                base.Rotate(degrees);

                object after = host.StoryCardData.Clone();
                ((StoryCard)after).RotationAngle = host.rotate.Angle;

                if (before != after)
                    host.IndexCardDropped(host, new IndexCardDropEventArgs(host.ID, host.ParentID,
                        host.CenterAbsolute, host.StoryCardData.RotationAngle, before, after));
            }

            /// <summary>
            /// Resizes the card and propagates the change.
            /// </summary>
            /// <param name="width">The parameter by which the card should widen.</param>
            /// <param name="height">The parameter by which the card should heighten (sp?).</param>
            public override void Resize(double width, double height)
            {
                object before = host.StoryCardData.Clone();
                object after = host.StoryCardData.Clone();

                base.Resize(width, height);

                if ((int)(((StoryCard)before).Width) != (int)host.Width || 
                    (int)(((StoryCard)before).Height) != (int)host.Height)
                {
                    host.StoryCardData.Width = host.Width;
                    host.StoryCardData.Height = host.Height;

                    ((StoryCard)after).Width = host.Width;
                    ((StoryCard)after).Height = host.Height;

                    if (before != after)
                        host.StoryCardData.Notify(IndexCardDataObject.SIZE_PROPERTY, before, after);
                }
            }

            /// <summary>
            /// Returns information that I can't reliably get otherwise.
            /// </summary>
            /// <returns>The position and rotation information for the storycard.</returns>
            protected override string GetHelpTextCore()
            {
                return 
                      "\n\tActualEffort="           + host.StoryCardData.ActualEffort
                    + "\n\tBackground="             + host.StoryCardData.Background
                    + "\n\tBestCaseEstimate="       + host.StoryCardData.BestCaseEstimate
                    + "\n\tCardOwner="              + host.StoryCardData.CardOwner
                    //+ "CurrentSideUp="            + host.StoryCardData.CurrentSideUp
                    + "\n\tDescription="            + host.StoryCardData.Description
                    //+ "FitID="                    + host.StoryCardData.FitID
                    + "\n\tHeight="                 + host.StoryCardData.Height
                    //+ "\n\tID="                   + host.StoryCardData.ID
                    + "\n\tLocationX="              + host.StoryCardData.LocationX
                    + "\n\tLocationY="              + host.StoryCardData.LocationY
                    + "\n\tMostLikelyEstimate="     + host.StoryCardData.MostlikelyEstimate
                    + "\n\tName="                   + host.StoryCardData.Name
                    + "\n\tParent="                 + host.StoryCardData.Parent
                    //+ "\n\tRemainingEffort"         + host.StoryCardData.RemainingEffort
                    + "\n\tRotation="               + host.RotationAngle
                    + "\n\tStatus="                 + host.StoryCardData.Status
                    + "\n\tWidth="                  + host.StoryCardData.Height
                    + "\n\tWorstCaseEstimate="      + host.StoryCardData.WorstCaseEstimate
                    + "\n"; 
            }
        }

        #endregion

        public void CardMinimized(bool isMinimized)
        {
         
            if (!isMinimized)
            {

                this.MinHeight = CardConstants.DEFAULT_MINIMIZED_CARD_HEIGHT;
                /*     this.Height = 100;
                     this.canvas.Height = 98;
                     this.grid.Height = 98;
                     this.highlight.Height = 114;*/
                this.resizerHandle.IsEnabled = false;
                this.isResized = false;
                double dx = this.MinWidth - this.Width;
                double dy = this.MinHeight - this.Height;
                this.Resize(ref dx,ref dy );
                this.refitCardCenterAndAbsolutePosition(dx,dy);
                this.translateOnlyArea.VerticalAlignment = VerticalAlignment.Top;
                //reset the interface
                this.handwritingSwitchButton.Opacity = 0;
                this.handwritingSwitchButton.IsEnabled = false;

                this.resizerHandle.Opacity = 0;
                this.resizerHandle.IsHitTestVisible = false;
                this.statusButton.Opacity = 1;
            //    this.ownerComboBox.IsHitTestVisible = true;
           //     this.grid.
               
                isResized = false;
                //     this.overlay.Height = 100; 
                this.isMinimized = true;
                /*       if (isLocalCall)
                       {
                           this.app.Persister.UpdateStoryCard(this.StoryCardData);
                       }*/

            }
            else
            {
                isResized = true;
                //         this.MinHeight = 320;
                this.MinHeight = CardConstants.STORYCARD_DEFAULT_HEIGHT;
                double dx = this.MinWidth - this.Width;
                double dy = CardConstants.STORYCARD_DEFAULT_HEIGHT - this.storycard.Height;
                this.Resize(ref dx,ref dy );
                this.refitCardCenterAndAbsolutePosition(dx, dy);
                this.translateOnlyArea.VerticalAlignment = VerticalAlignment.Center;
                this.handwritingSwitchButton.Opacity = 1;
                this.handwritingSwitchButton.IsEnabled = true;
                this.resizerHandle.Opacity = 1;
                this.resizerHandle.IsEnabled = true;
                this.resizerHandle.IsHitTestVisible = true;
                this.statusButton.Opacity = 1;
                this.statusButton.IsEnabled = true;
                //       this.overlay.Height = 320;
                this.resizerHandle.IsHitTestVisible = true;
                this.isMinimized = false;
            }


        }

        #region Dot Voting

        public void ClearVoteDots()
        {

            UIElement[] items = new UIElement[canvas.Children.Count];
            canvas.Children.CopyTo(items, 0);
            
            foreach(UIElement item in items)
            {
                if(item is Ellipse)
                {
                    canvas.Children.Remove(item);
                }
            }
        }

        public void drawVoteDot(int x, int y)
        {
            Ellipse dot = new Ellipse();
            dot.Stroke = System.Windows.Media.Brushes.Gray;
            dot.Fill = System.Windows.Media.Brushes.Gray;
            dot.Width = 25;
            dot.Height = 25;
            Canvas.SetTop(dot, y - 10);
            Canvas.SetLeft(dot, x - 10);
            canvas.Children.Add(dot);
        }

        #endregion

        #region MultiTouchEvent

        public override void OnTouchDown(Point p)
        {
            base.OnTouchDown(p);
     //      Point relatedPoint =  this.getPosition(p,this);
    //       Point anotherPoint = this.getPosition(p, resizerHandle);
            Point actual = this.getPosition(p,this);

            //bring it to front
            app.BringToFront(this);
            //Console.WriteLine(actual.X.ToString());               //this test was left uncommented!
            //if you move this card on top of other cards only
            //this one will react, otherwise you drag the rest with
            //you like a fish-net
            IsActive = true;

            if (!IsPinned)
            {
                //don't show the translate only area if the card
                //is pinned or it'll confuse the user during handwriting
                translateOnlyArea.Opacity = 1;
            }
            else
            {
                //if the card is pinned just quit the function
                return;
            }

            //if the card is currently in an animated movement this saves
            //the current position of the card and fires the DropEvent to notify
            //the application of the position update
            if (animationStoryBoard.GetCurrentState(this) == ClockState.Active)
            {
                //Yippie-Ki-Yay ... stops the card from jumping if
                //you click on label or resizerhandle
                rotate.Angle = (double)rotate.GetValue(RotateTransform.AngleProperty);
                trans.X = (double)trans.GetValue(TranslateTransform.XProperty);
                trans.Y = (double)trans.GetValue(TranslateTransform.YProperty);

                animationStoryBoard.Stop(this);

                //TODO change copies only!
                object before = StoryCardData.Clone();
                //StoryCardData.LocationX = trans.X;
                //StoryCardData.LocationY = trans.Y;
                //StoryCardData.RotationAngle = rotate.Angle;
                StoryCard after = (StoryCard)StoryCardData.Clone();

                after.LocationX = trans.X / Properties.Settings.Default.Scale;
                after.LocationY = trans.Y / Properties.Settings.Default.Scale;
                after.RotationAngle = rotate.Angle;

                IndexCardDropped(this, new IndexCardDropEventArgs(ID, ParentID, RelativeToAbsoluteCoordinates(actual), StoryCardData.RotationAngle, before, after));
            }

            //clear the list of keyframes or you'll get unexpected
            //results
            translateXAnimation.KeyFrames.Clear();
            translateYAnimation.KeyFrames.Clear();
            rotateAnimation.KeyFrames.Clear();

            IsTossed = false;
            //resize
            if (resizerHandle.IsInsideResizerHandleArea(this.getPosition(p,resizerHandle)) && !isMinimized)
            {
                IsResized = true;
                IsTranslated = false;
                isDragged = false;      //some very strange behavior occurs without this
                //       this.originalTop = ((Canvas)(((AgilePlannerMainWindow)this.parentWindow).getCanvas())).GetTop(this);
                this.originalTop = this.trans.Y;
                this.orignialLeft = this.trans.X;

            }
            //translate only
            else if (translateOnlyArea.IsInsideTranslateOnlyArea(this.getPosition(p,translateOnlyArea)))
            {
                IsTranslated = true;
                IsResized = false;
            }

            //RNT
            else
            {
                IsTranslated = false;
                IsResized = false;
            }

            previous = RelativeToAbsoluteCoordinates(actual);
            previousRelative = actual;

            startTime = DateTime.Now;  //for tossing

            //for tossing we watch the last few mouse coordinates
            recentPoints.Clear();
            recentTime.Clear();
            AddMousePoint(RelativeToAbsoluteCoordinates(actual));
            AddTimePoint(DateTime.Now);
            
        }

        public override void OnTouchMove(Point p)
        {
            base.OnTouchMove(p);
    //        Point actual = RelativeToAbsoluteCoordinates(e.GetPosition(this));
            Point actual = p;
            Point actualRelative = this.getPosition(p,this);

            if (IsActive)
            {
                //don't do anything when the card is pinned but
                //update the last point
                if (IsPinned)
                {
                    previous = actual;
                    previousRelative =this.getPosition(p,this);
                    AddMousePoint(actual);
                    AddTimePoint(DateTime.Now);
                    return;
                }

                //ignore very small movements (should help
                //compensate the imprecision of the DViTs)
                if (Util.GetDistance2D(previous, actual) < CardConstants.MIN_MOVEMENT_THRESHOLD)
                {
                    previous = actual;
                    previousRelative = this.getPosition(p, this);
                    AddMousePoint(actual);
                    AddTimePoint(DateTime.Now);
                    return;
                }

                //TODO corrective movement
                if (IsResized)
                {
                    //determine the values for horizontal and vertical resize as
                    //the relative change between the previous mouse position and the actual
                    //on the card
                    double dx = actualRelative.X - previousRelative.X;
                    double dy = actualRelative.Y - previousRelative.Y;

                    //make sure to keep the 3/2 aspect ratio
                    /*                  if (dx / dy > DEFAULT_ASPECT_RATIO)
                                          dy = dx * 1 / DEFAULT_ASPECT_RATIO;
                                      else
                                          dx = dy * DEFAULT_ASPECT_RATIO;*/

                    //       this.trans.X  += dx;
                    //  this.trans.Y -=dy;
                    Resize(ref dx, ref dy);
                    this.refitCardCenterAndAbsolutePosition(dx, dy);
                   (this.app).SynchronizeResizingCard(this, p,257);

                }
                else
                {
                    IsDragged = true;
                    ApplyRNT(actual);
                    (this.app).SynchornizeMovingCard(this, p, 257);

                }

                //used for keeping track of the movement of the card
                AddMousePoint(actual);
                AddTimePoint(DateTime.Now);
                previous = actual;
                previousRelative = this.getPosition(p, this);
            }
        }

        public override void OnTouchUp(Point p)
        {
            base.OnTouchUp(p);
            object before = null;
            object after = null;

            translateOnlyArea.Opacity = 0;

            IsActive = false;

            if (IsPinned)
                return;

            Point actual = this.getPosition(p, this);

            if (IsResized)
            {
                before = StoryCardData.Clone();
                after = StoryCardData.Clone();

                ((StoryCard)after).Width = Width;
                ((StoryCard)after).Height = Height;
                if ((int)(((StoryCard)before).Width) != (int)Width || (int)(((StoryCard)before).Height) != (int)Height)
                {//change the data object
                    this.StoryCardData.Width = Width;
                    this.StoryCardData.Height = Height;

                    if ((int)(((StoryCard)before).LocationX) != (int)(LocationX / Properties.Settings.Default.Scale) || (int)(((StoryCard)before).LocationY) != (int)(LocationY / Properties.Settings.Default.Scale))
                    {
                        this.StoryCardData.LocationX = LocationX / Properties.Settings.Default.Scale;
                        this.StoryCardData.LocationY = LocationY / Properties.Settings.Default.Scale;
                        after = StoryCardData.Clone();
                    }
                    StoryCardData.Notify(IndexCardDataObject.SIZE_PROPERTY, before, after);
                }
                IsResized = false;
                return;
            }

            if (IsDragged)
            {
                before = StoryCardData.Clone();
                after = StoryCardData.Clone();

                ((StoryCard)after).LocationX = trans.X / Properties.Settings.Default.Scale;
                ((StoryCard)after).LocationY = trans.Y / Properties.Settings.Default.Scale;
                ((StoryCard)after).RotationAngle = rotate.Angle;

                peer.OnTransform(before, after);

                IsDragged = false;
            }

            AddMousePoint(RelativeToAbsoluteCoordinates(actual));
            AddTimePoint(DateTime.Now);

            //check if the movement was fast enough to count as tossing
            double length = Util.GetDistance2D(recentPoints[0], recentPoints[recentPoints.Count - 1]);

            if (!IsResized && IsTossingEnabled && (length > CardConstants.STATIC_FRICTION_COEFFICIENT))
            {
                IsTossed = true;

                //vector along which to move the card
                tossingVector = new Point(recentPoints[recentPoints.Count - 1].X - recentPoints[0].X,
                    recentPoints[recentPoints.Count - 1].Y - recentPoints[0].Y);

                //setting up the vector for the initial moment of the tossing RNT
                initVector = new Point(recentPoints[recentPoints.Count - 1].X - CenterAbsolute.X,
                    recentPoints[recentPoints.Count - 1].Y - CenterAbsolute.Y);

                initAngle = RotationAngle;

                //        endTime = DateTime.Now;

                if (IsTranslated)
                {
                    ApplyTranslateOnlyTossing();
                }
                else
                {
                    ApplyRNTTossing();
                }
            }
            else
            {
                if (before != null && after != null)
                    //if the card is only moved and not tossed then fire the DropEvent
                    IndexCardDropped(this, new IndexCardDropEventArgs(ID, ParentID, RelativeToAbsoluteCoordinates(actual), StoryCardData.RotationAngle, before, after));
            }

            IsTranslated = false;

            //make sure that we don't have any old points in our watchlist
            recentPoints.Clear();
            recentTime.Clear();
        }

   /*     private Point getPosition(Point p, UIElement element)
        {
                 //           Point relativePoint = (Point)this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new GetRelativePoint(this.windowCanvas.TranslatePoint),p, (UIElement)activatedCard);

     //       return (Point)((AgilePlannerMainWindow)(this.app)).Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render,new GetPosition(((AgilePlannerMainWindow)(this.app)).getCanvas().TranslatePoint),p, element);
            return ((AgilePlannerMainWindow)(this.app)).getCanvas().TranslatePoint(p, element); 
        }*/
        #endregion
    }
}